package com.bzg.baseSpringComponent.typeConverter;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConverterFactory;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.lang.Nullable;
import org.springframework.util.NumberUtils;

/**
 * 类型转换器
 * */
public class ConverterStyle {

	@Value("test")
	private User user;  // value注解的注入也支持这些类型转换器，可以将value中的字符串转经过对应的类型转换器转为所需对象

	public static void main(String[] args) {
//		// jdk属性编辑器
//		StringToUserPropertyEditor stringToUserPropertyEditor = new StringToUserPropertyEditor();
//		stringToUserPropertyEditor.setAsText("zhangsan");
//		User value = (User)stringToUserPropertyEditor.getValue();
//		System.out.println(value);

		// spring的Converter
		StringToUserConverter stringToUserConverter = new StringToUserConverter();
		boolean matches = stringToUserConverter.matches(TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(User.class));
		if(matches) {
			Object zhangsan = stringToUserConverter.convert("zhangsan", TypeDescriptor.valueOf(String.class), TypeDescriptor.valueOf(User.class));
			System.out.println(zhangsan);
		}
		// 一般来说spring的类型转化器我们不会像上面这样直接拿来使用，因为spring提供了三种converter，所以spring提供了一个统一的接口
		// 来管理这三种类型转换器，使我们面向同一接口进行使用。这个接口就是ConversionService。ConversionService本质是将1：1，1：N
		// 这两种类型转换器也适配成一个N:N的类型转换器，使得他可以对各种类型转换器通过统一的api进行处理
		GenericConversionService genericConversionService = new GenericConversionService();
		ConverterFactory stringToNumberConverterFactory = new StringToNumberConverterFactory();
		genericConversionService.addConverterFactory(stringToNumberConverterFactory);
		genericConversionService.canConvert(String.class,Long.class);
		Long convert = genericConversionService.convert("1", Long.class);
		System.out.println(convert);

	}
}
final class StringToNumberConverterFactory implements ConverterFactory<String, Number> {

	@Override
	public <T extends Number> Converter<String, T> getConverter(Class<T> targetType) {
		return new StringToNumberConverterFactory.StringToNumber<>(targetType);
	}


	private static final class StringToNumber<T extends Number> implements Converter<String, T> {

		private final Class<T> targetType;

		public StringToNumber(Class<T> targetType) {
			this.targetType = targetType;
		}

		@Override
		@Nullable
		public T convert(String source) {
			if (source.isEmpty()) {
				return null;
			}
			return NumberUtils.parseNumber(source, this.targetType);
		}
	}

}